package com.shiguiwu.springboot3;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.TypeUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.nacos.common.http.param.MediaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shiguiwu.springboot3.enums.ApiErrorCode;
import com.shiguiwu.springboot3.feign.CustomSpringDecoder;
import com.shiguiwu.springboot3.properties.OpenfeignProperties;
import com.shiguiwu.springboot3.util.R;
import feign.FeignException;
import feign.Response;
import feign.Util;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.support.HttpMessageConverterCustomizer;
import org.springframework.context.ConfigurableApplicationContext;
import tk.mybatis.spring.annotation.MapperScan;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.nio.charset.StandardCharsets;

/**
 * @description: 启动类
 * @author: stone
 * @date: Created by 2023/7/2 23:00
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springboot3
 */
@SpringBootApplication
@EnableFeignClients(value = "com.shiguiwu.springboot3.feign")
@MapperScan(basePackages = "com.shiguiwu.springboot3.mapper")
@Slf4j
public class OrderAppStarter {

    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(OrderAppStarter.class, args);
        OpenfeignProperties bean = run.getBean(OpenfeignProperties.class);
        log.info("bean====》 {}", bean);

    }



    public Decoder decoder(ObjectFactory<HttpMessageConverters> customizers, ObjectProvider<HttpMessageConverterCustomizer> messageConverters, ObjectMapper objectMapper) {
        return new CustomDecoder(new CustomSpringDecoder(customizers, messageConverters), objectMapper);
    }


    @Slf4j
    public static class CustomDecoder implements Decoder {

        private final ObjectMapper objectMapper;

        private final Decoder delegate;

        public CustomDecoder(Decoder feignDecoder, ObjectMapper objectMapper) {
            this.delegate = feignDecoder;
            this.objectMapper = objectMapper;

        }

        @Override
        public Object decode(Response response, Type type) throws IOException {
            if (response.headers().get("Content-Type").stream()
                    .anyMatch(value -> value.equalsIgnoreCase(MediaType.TEXT_HTML))) {
                return decodeHtml(response, type);

            } else {
                // 对于非 text/html 的Content-Type，我们使用默认的解码器
                return delegate.decode(response, type);
            }
        }

        //无bug
        private Object decodeHtml(Response response, Type type) throws IOException {
            if (!(type instanceof Class) && !(type instanceof ParameterizedType) && !(type instanceof WildcardType)) {
                throw new DecodeException(response.status(), "type is not an instance of Class or ParameterizedType: " + type, response.request());
            }

            // 这里添加你的解析逻辑，将输入流解析为你的自定义对象
            byte[] allBytes = response.body().asInputStream().readAllBytes();
            String resultString = new String(allBytes, StandardCharsets.UTF_8);
            //判断是否是json数据
            boolean typeJSON = JSONUtil.isTypeJSON(resultString);

            //判断是否是包装类型或者是String类
            Class<?> aClass = TypeUtil.getClass(type);
            if (!typeJSON) {
                return ObjectUtil.deserialize(response.body().asInputStream().readAllBytes(), aClass);
            }
            //json类型，2种情况,1去掉一层，2，不去一层
            Object result = ObjectUtil.deserialize(response.body().asInputStream().readAllBytes(), aClass);
            if (aClass.getName().contains("aClass.....")) {
                return ObjectUtil.deserialize(response.body().asInputStream().readAllBytes(), aClass);
            }
            return ReflectUtil.invoke(result, "methodName");
        }

    }


    public static class FeignResultDecoder implements Decoder {

        @Override
        public Object decode(Response response, Type type) throws IOException, FeignException {
            if (response.body() == null) {
                return null;
            }
            String bodyStr = Util.toString(response.body().asReader(Util.UTF_8));

            //判断是否是包装类型或者是String类
            boolean simpleValueType = type instanceof Class<?> && ClassUtil.isSimpleValueType((Class<?>) type);

            boolean typeJSON = JSONUtil.isTypeJSON(bodyStr);
            R result;
            if (simpleValueType && typeJSON) {
                result = JSONUtil.toBean(bodyStr, R.class, true);
            } else {
                result = JSONUtil.toBean(bodyStr, R.class, true);
            }
            if (!ApiErrorCode.SUCCESS.getCode().equals(result.getCode())) {
                throw new DecodeException(response.status(), "接口返回错误：" + result.getMsg(), response.request());
            }

            return JSONUtil.toBean((JSONObject) result.getData(), (Class<?>) type);
        }
    }

}
